package com.person.jiaiplan.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.person.jiaiplan.assembler.ExpensesAssembler;
import com.person.jiaiplan.mapper.ExpensesPlanMapper;
import com.person.jiaiplan.pojo.dto.expenses.ExpensesAddPlanReqDTO;
import com.person.jiaiplan.pojo.dto.expenses.ExpensesPlanQueryReqDTO;
import com.person.jiaiplan.pojo.dto.expenses.ExpensesPlanQueryResDTO;
import com.person.jiaiplan.pojo.entity.ExpensesCountLogs;
import com.person.jiaiplan.pojo.entity.ExpensesPlan;
import com.person.jiaiplan.pojo.signle.SignleSnowFlake;
import com.person.jiaiplan.service.ExpensesCountLogsService;
import com.person.jiaiplan.service.ExpensesPlanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

@Service
public class ExpensesPlanServiceImpl extends ServiceImpl<ExpensesPlanMapper, ExpensesPlan> implements ExpensesPlanService {

    @Autowired
    private ExpensesCountLogsService expensesCountLogsService;


    @Override
    public Boolean addPlan(ExpensesAddPlanReqDTO reqDTO) {
        Boolean result =true;
        ExpensesPlan expensesPlan = ExpensesAssembler.INSTANCE.reqDTO2ExpensesPlan(reqDTO);

        if (reqDTO.getPlanStartTime() != null) {
            expensesPlan.setStartTime(DateUtil.parse(reqDTO.getPlanStartTime()));
        }

        if (reqDTO.getPlanFinishTime() != null) {
            expensesPlan.setEndTime(DateUtil.parse(reqDTO.getPlanFinishTime()));
        }
        expensesPlan.setCreateTime(DateUtil.date());
        expensesPlan.setId(SignleSnowFlake.getSnowflakeId());
        if (expensesPlan.getExpensesType() == 1) {
            expensesPlan.setStatus(1);
        } else {
            expensesPlan.setStatus(2);
        }

        if (2 == reqDTO.getExpensesType()) {
            // 开始时间和结束时间相差的月份作为分期数
            long months = DateUtil.betweenMonth(expensesPlan.getStartTime(), expensesPlan.getEndTime(), true);
            expensesPlan.setInstallmentsNo((int) months);
        }
        result = this.save(expensesPlan);
        // 如果新建的是每日的计划花销，则同时建一个统计花销
        if (1 == reqDTO.getExpensesType()) {
            result = result && createExpensesCountLogs(expensesPlan);
        }
        // 如果新建的是分期的花销，则同时建一个统计花销
        if (2 == reqDTO.getExpensesType()) {
            result = result && createStagingCountLogs(expensesPlan);
        }
        return result;
    }

    @Override
    public Boolean editPlan(ExpensesAddPlanReqDTO reqDTO) {
        ExpensesPlan expensesPlan = this.getById(reqDTO.getId());
        if (expensesPlan == null) {
            return false;
        }
        if (reqDTO.getPlanStartTime() != null) {
            expensesPlan.setStartTime(DateUtil.parse(reqDTO.getPlanStartTime()));
        }
        if (reqDTO.getPlanFinishTime() != null) {
            expensesPlan.setEndTime(DateUtil.parse(reqDTO.getPlanFinishTime()));
        }
        expensesPlan.setRemark(reqDTO.getRemark());
        expensesPlan.setEstimatedAmount(new BigDecimal(reqDTO.getEstimatedAmount()));
        expensesPlan.setContent(reqDTO.getContent());
        expensesPlan.setExpensesType(reqDTO.getExpensesType());
        expensesPlan.setUpdateTime(DateUtil.date());
        if (2 == reqDTO.getExpensesType()) {
            // 开始时间和结束时间相差的月份作为分期数
            long months = DateUtil.betweenMonth(expensesPlan.getStartTime(), expensesPlan.getEndTime(), true);
            expensesPlan.setInstallmentsNo((int) months);
        }
        // 编辑的时候，需要同时处理统计花销的数据
        if (1 == reqDTO.getExpensesType() || 2 == reqDTO.getExpensesType()){
            handelExpensesCountLogs(expensesPlan);
        }
        return this.updateById(expensesPlan);
    }

    @Override
    public List<ExpensesPlanQueryResDTO> queryExpensesPlan(ExpensesPlanQueryReqDTO reqDTO) {

        // 默认查询本月的数据
        if (StrUtil.isBlank(reqDTO.getStartTime()) || StrUtil.isBlank(reqDTO.getEndTime())) {
            reqDTO.setStartTime(DateUtil.format(DateUtil.beginOfMonth(DateUtil.date()), "yyyy-MM-dd"));
            reqDTO.setEndTime(DateUtil.format(DateUtil.endOfMonth(DateUtil.date()), "yyyy-MM-dd"));
        }

        LambdaQueryWrapper<ExpensesPlan> queryWrapper = Wrappers.<ExpensesPlan>lambdaQuery();
        if (reqDTO.getExpensesType() != null) {
            queryWrapper.eq(ExpensesPlan::getExpensesType, reqDTO.getExpensesType());
        }
        queryWrapper.between(ExpensesPlan::getCreateTime, DateUtil.beginOfDay(DateUtil.parseDate(reqDTO.getStartTime())), DateUtil.endOfDay(DateUtil.parseDate(reqDTO.getEndTime())))
                .orderByAsc(ExpensesPlan::getCreateTime);


        List<ExpensesPlan> expensesPlans = this.list(queryWrapper);
        if (expensesPlans == null || expensesPlans.size() == 0) {
            return new LinkedList<>();
        }
        List<ExpensesPlanQueryResDTO> expensesPlanQueryResDTOS = createExpensesPlanQueryResDTOS(expensesPlans);

        return expensesPlanQueryResDTOS;
    }

    /**
     * 处理统计花销的数据
     * @param expensesPlan
     */
    private void handelExpensesCountLogs(ExpensesPlan expensesPlan){
        ExpensesCountLogs expensesCountLogs = expensesCountLogsService.getOne(Wrappers.<ExpensesCountLogs>lambdaQuery().eq(ExpensesCountLogs::getPlanId,expensesPlan.getId()));
        if (expensesCountLogs == null){
            return;
        }
        if (expensesPlan.getExpensesType() == 1){
            expensesCountLogs.setContent(expensesPlan.getContent());
            expensesCountLogs.setEstimatedAmount(expensesPlan.getEstimatedAmount());
            expensesCountLogs.setRealAmount(expensesPlan.getEstimatedAmount());
        }
        if (expensesPlan.getExpensesType() == 2){
            expensesCountLogs.setContent(expensesPlan.getContent());
            expensesCountLogs.setEstimatedAmount(expensesPlan.getEstimatedAmount());
            expensesCountLogs.setRealAmount(expensesPlan.getEstimatedAmount().divide(new BigDecimal(expensesPlan.getInstallmentsNo()),2, RoundingMode.HALF_UP));
            expensesCountLogs.setPlanStartTime(expensesPlan.getStartTime());
            expensesCountLogs.setPlanEndTime(expensesPlan.getEndTime());
        }
        expensesCountLogsService.updateById(expensesCountLogs);

    }

    /**
     * 创建一个分期的统计对象
     * @param expensesPlan
     * @return
     */
    private Boolean createStagingCountLogs(ExpensesPlan expensesPlan){
        ExpensesCountLogs expensesCountLogs = new ExpensesCountLogs();
        expensesCountLogs.setId(SignleSnowFlake.getSnowflakeId());
        expensesCountLogs.setPlanId(expensesPlan.getId());
        expensesCountLogs.setEstimatedAmount(expensesPlan.getEstimatedAmount().divide(new BigDecimal(expensesPlan.getInstallmentsNo()),2, RoundingMode.HALF_UP));
        expensesCountLogs.setRealAmount(expensesPlan.getEstimatedAmount().divide(new BigDecimal(expensesPlan.getInstallmentsNo()),2, RoundingMode.HALF_UP));
        expensesCountLogs.setContent(expensesPlan.getContent());
        expensesCountLogs.setExpensesType(expensesPlan.getExpensesType());
        expensesCountLogs.setPlanStartTime(expensesPlan.getStartTime());
        expensesCountLogs.setPlanEndTime(expensesPlan.getEndTime());
        expensesCountLogs.setCreateTime(DateUtil.date());
        return expensesCountLogsService.save(expensesCountLogs);
    }

    /**
     * 每日计划更新一条统计记录
     *
     * @param expensesPlan
     */
    private Boolean createExpensesCountLogs(ExpensesPlan expensesPlan) {
        ExpensesCountLogs expensesCountLogs = new ExpensesCountLogs();
        expensesCountLogs.setId(SignleSnowFlake.getSnowflakeId());
        expensesCountLogs.setPlanId(expensesPlan.getId());
        expensesCountLogs.setEstimatedAmount(expensesPlan.getEstimatedAmount());
        expensesCountLogs.setRealAmount(expensesPlan.getEstimatedAmount());
        expensesCountLogs.setContent(expensesPlan.getContent());
        expensesCountLogs.setExpensesType(expensesPlan.getExpensesType());
        expensesCountLogs.setCreateTime(DateUtil.date());
        return expensesCountLogsService.save(expensesCountLogs);

    }

    /**
     * 创建查询对象
     *
     * @param expensesPlans
     * @return
     */
    private List<ExpensesPlanQueryResDTO> createExpensesPlanQueryResDTOS(List<ExpensesPlan> expensesPlans) {
        List<ExpensesPlanQueryResDTO> expensesPlanQueryResDTOS = new LinkedList<>();

        expensesPlans.stream().forEach(expensesPlan -> {
            ExpensesPlanQueryResDTO expensesPlanQueryResDTO = new ExpensesPlanQueryResDTO();
            expensesPlanQueryResDTO.setId(String.valueOf(expensesPlan.getId()));
            expensesPlanQueryResDTO.setExpensesType(expensesPlan.getExpensesType());
            expensesPlanQueryResDTO.setRemark(expensesPlan.getRemark());
            expensesPlanQueryResDTO.setContent(expensesPlan.getContent());
            expensesPlanQueryResDTO.setCreateTime(DateUtil.format(expensesPlan.getCreateTime(), "yyyy-MM-dd"));
            expensesPlanQueryResDTO.setStatus(expensesPlan.getStatus());
            expensesPlanQueryResDTO.setPlanStartTime(DateUtil.format(expensesPlan.getStartTime(), "yyyy-MM-dd"));
            expensesPlanQueryResDTO.setPlanFinishTime(DateUtil.format(expensesPlan.getEndTime(), "yyyy-MM-dd"));
            expensesPlanQueryResDTO.setEstimatedAmount(expensesPlan.getEstimatedAmount().toString());
            String time = "-";
            if (expensesPlan.getStartTime() != null) {
                time = DateUtil.format(expensesPlan.getStartTime(), "yyyy-MM-dd");
                if (expensesPlan.getEndTime() != null) {
                    time = time + " - " + DateUtil.format(expensesPlan.getEndTime(), "yyyy-MM-dd");
                }
            }
            expensesPlanQueryResDTO.setTime(time);
            String estimatedAmount = expensesPlan.getEstimatedAmount().toString() + " ￥";
            if (expensesPlan.getInstallmentsNo() != null) {
                estimatedAmount += " (" + expensesPlan.getInstallmentsNo() + "期 ) 每期" + expensesPlan.getEstimatedAmount().divide(BigDecimal.valueOf(expensesPlan.getInstallmentsNo()), RoundingMode.HALF_UP).toString() + "￥";
            }
            expensesPlanQueryResDTO.setEstimatedAmountStr(estimatedAmount);
            expensesPlanQueryResDTOS.add(expensesPlanQueryResDTO);

        });
        // 按照类型排序
        CollectionUtil.sort(expensesPlanQueryResDTOS, Comparator.comparing(ExpensesPlanQueryResDTO::getStatus, Comparator.reverseOrder())
                .thenComparing(ExpensesPlanQueryResDTO::getExpensesType));

        return expensesPlanQueryResDTOS;
    }
}
